#include "mystdio.h"

//模拟c语言封装接口实现行刷新


//打开接口
FILE_* fopen_(const char* path_name,const char* mode)
{
    int flags=0;
    int defaultMode=0666; //权限
    if(strcmp(mode,"r")==0)
    {
        flags|=O_RDONLY;
    }
    else if(strcmp(mode,"w")==0)
    {
        flags|=(O_WRONLY|O_CREAT|O_TRUNC);
    }
    else if(strcmp(mode,"a")==0)
    {
        flags|=(O_WRONLY|O_CREAT|O_APPEND);
    }
    else 
    {
        //TO DO
    }

    //打开文件
    int fd=0;
    if(flags & O_RDONLY)
    {
        //只读不需要设置权限
       fd=open(path_name,flags);
    }
    else 
    {
        fd=open(path_name,flags,defaultMode);
    }

    //如果文件创建失败
    if(fd<0)
    {
        const char* err=strerror(errno);
        write(2,err,strlen(err));
        return NULL; //c语言接口fopen打开文件失败会返回NULL
    }

    FILE_* fp=(FILE_*)malloc(sizeof(FILE_));
    assert(fp);

    //初始化部分
    fp->flags=SYNC_LINE; //默认设置成为行刷新
    fp->fileno=fd;
    fp->cap=SIZE;
    fp->size=0;
    memset(fp->buffer,0,SIZE);

    return fp; //C语言接口打开一个文件就会返回一个FILE*的指针

}


//写入
void fwrite_(const void* ptr,int num,FILE_* fp)
{
    //1.写入到缓冲区中 
    //要把我们的数据块（可以是字符串）中的数据写到缓冲区里面
    memcpy(fp->buffer+fp->size,ptr,num); //拷贝函数,不考虑缓冲区溢出的问题
    fp->size+=num;


    //2.判断是否要刷新
    if(fp->flags & SYNC_NOW)
    {
        //立即刷新，直接调用write函数就行
        write(fp->fileno,fp->buffer,fp->size);
        fp->size=0; //清空缓冲区，惰性释放
         
    }
    else if(fp->flags & SYNC_FULL) 
    {
        //缓冲区满再刷新
        if(fp->size==fp->cap)
        {
            write(fp->fileno,fp->buffer,fp->size);
            fp->size=0;
        }
    }
    else if(fp->flags & SYNC_LINE)
    {
        //按行刷新,判断buffer里面的size-1的位置是不是以\n结尾
        //暂时不考虑在字符串中有\n的情况（demo）
        if(fp->buffer[fp->size-1]=='\n')
        {
            write(fp->fileno,fp->buffer,fp->size);
            fp->size=0;
        }     
    }
    else {

    }
    
}



void fflush_(FILE_* fp)
{
    //刷新
    if(fp->size>0)
    {
        //就是把文件里面的内容写到系统里
        write(fp->fileno,fp->buffer,fp->size);
        fsync(fp->fileno); //将数据强制要求操作系统进行外设刷新
        fp->size=0; //刷新完将缓冲区中数据清零
    }
    //TO DO
}


void fclose_(FILE_* fp)
{
    //关闭文件前先要做刷新
    fflush_(fp);
    close(fp->fileno);
}

